package com.yang.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yang.dao.entity.*;
import com.yang.dao.mapper.CommodityMapper;
import com.yang.dto.req.CommodityPageQueryReqDTO;
import com.yang.dto.req.CommoditySaveReqDTO;
import com.yang.dto.req.CommodityUpdateReqDTO;
import com.yang.dto.resp.CommodityPageQueryRespDTO;
import com.yang.service.CommodityService;
import com.yang.utils.AliOssUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

/**
 * 商品业务实现层
 * 作者：孤城暖阳y
 * 开发时间：2025-03-11
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class CommodityServiceImpl extends ServiceImpl<CommodityMapper, CommodityDO> implements CommodityService {

    private final CommodityMapper commodityMapper;
    private final MongoTemplate mongoTemplate;

    @Override
    public IPage<CommodityPageQueryRespDTO> pageQueryCommodities(CommodityPageQueryReqDTO requestParam) {
        // 构建带表别名的查询条件
        QueryWrapper<CommodityDO> queryWrapper = new QueryWrapper<CommodityDO>()
                .like(StringUtils.isNotBlank(requestParam.getCommodityTitle()),
                        "c.commodity_title", requestParam.getCommodityTitle())
                .eq(Objects.nonNull(requestParam.getCategoryId()),
                        "c.category_id", requestParam.getCategoryId())
                .between(Objects.nonNull(requestParam.getMinPrice()) && Objects.nonNull(requestParam.getMaxPrice()),
                        "c.commodity_price", requestParam.getMinPrice(), requestParam.getMaxPrice());

        // 执行联表分页查询（直接返回已映射的DTO结果）
        IPage<CommodityPageQueryRespDTO> respDTOIPage = commodityMapper.selectCommodityWithCategory(
                new Page<>(requestParam.getCurrent(), requestParam.getSize()),
                queryWrapper
        );

        // 获取MongoDB中skuId、name和valueName
        for (CommodityPageQueryRespDTO respDTO : respDTOIPage.getRecords()) {
            // mongoDB获取sku数据
            Query query = new Query(Criteria.where("commodityId").is(respDTO.getCommodityId()));
            List<SkusDO> skusDOS = mongoTemplate.find(query, SkusDO.class);
            // TODO 这里或许可以优化。其次MongoDB中skuId的数据类型是字符串类型后续需要改为长整型
            respDTO.setSkusDOS(skusDOS);
        }

        // 获取商品轮播图
        for (CommodityPageQueryRespDTO respDTO : respDTOIPage.getRecords()) {
            Query query = new Query(Criteria.where("commodityId").is(respDTO.getCommodityId()));
            List<CarouselImagesDO> carouselImagesDOS = mongoTemplate.find(query, CarouselImagesDO.class);
            respDTO.setImgUrl(carouselImagesDOS.getFirst().getImgUrl());
        }

        // 获取specs
        for (CommodityPageQueryRespDTO respDTO : respDTOIPage.getRecords()) {
            Query query = new Query(Criteria.where("commodityId").is(respDTO.getCommodityId()));
            List<SpecsDO> carouselImagesDOS = mongoTemplate.find(query, SpecsDO.class);
            respDTO.setSpecsDOS(carouselImagesDOS);
        }
        return respDTOIPage;
    }

    @Override
    @Transactional
    public void saveCommodity(CommoditySaveReqDTO reqDTO) {
        // 存入commodity表
        CommodityDO commodityDO = BeanUtil.copyProperties(reqDTO, CommodityDO.class);
        // 取列表第一个作为商品封面
        commodityDO.setCoverImage(reqDTO.getImgUrl().getFirst());
        // 取第一个sku的价格作为商品封面价格
        commodityDO.setCommodityPrice(reqDTO.getSkuList().getFirst().getPrice());
        commodityMapper.insert(commodityDO);

        // 新增SKU插入逻辑
        Long commodityId = commodityDO.getCommodityId();

        // 获取当前最大ID（使用MongoDB聚合查询优化性能）
        Aggregation skusAggregation = Aggregation.newAggregation(
                Aggregation.group().max("id").as("maxId")
        );
        AggregationResults<Map> skusResult = mongoTemplate.aggregate(
                skusAggregation,
                SkusDO.class,
                Map.class
        );

        // 计算起始ID（如果没有记录则从1开始）
        long currentMaxId = skusResult.getUniqueMappedResult() != null
                ? ((Number) skusResult.getUniqueMappedResult().get("maxId")).longValue()
                : 0L;
        AtomicLong skusIdGenerator = new AtomicLong(currentMaxId);
        // 批量插入SKU数据
        List<SkusDO> skusToInsert = reqDTO.getSkuList().stream()
                .map(sku -> {
                    SkusDO newSku = BeanUtil.copyProperties(sku, SkusDO.class);
                    newSku.setId(skusIdGenerator.incrementAndGet()); // ID自增
                    newSku.setSkuId(newSku.getId());
                    newSku.setCommodityId(commodityId);
                    return newSku;
                })
                .collect(Collectors.toList());
        mongoTemplate.insertAll(skusToInsert);

        // 获取carousel_images的最大id
        Aggregation imagesAggregation = Aggregation.newAggregation(
                Aggregation.group().max("id").as("maxId")
        );
        AggregationResults<Map> imagesResult = mongoTemplate.aggregate(
                imagesAggregation,
                CarouselImagesDO.class,
                Map.class
        );
        // 计算起始ID（如果没有记录则从1开始）
        currentMaxId = imagesResult.getUniqueMappedResult() != null
                ? ((Number) imagesResult.getUniqueMappedResult().get("maxId")).longValue()
                : 0L;
        AtomicLong imageIdGenerator = new AtomicLong(currentMaxId);
        // 插入carousel_images数据
        CarouselImagesDO newImage = new CarouselImagesDO()
                .setImgUrl(reqDTO.getImgUrl())
                .setId(imageIdGenerator.incrementAndGet()) // ID自增
                .setCommodityId(commodityId);
        mongoTemplate.save(newImage);

        // 获取specs的最大id
        Aggregation specsAggregation = Aggregation.newAggregation(
                Aggregation.group().max("id").as("maxId")
        );
        AggregationResults<Map> specsResult = mongoTemplate.aggregate(
                specsAggregation,
                SpecsDO.class,
                Map.class
        );
        // 计算起始ID（如果没有记录则从1开始）
        currentMaxId = specsResult.getUniqueMappedResult() != null
                ? ((Number) specsResult.getUniqueMappedResult().get("maxId")).longValue()
                : 0L;
        AtomicLong specsIdGenerator = new AtomicLong(currentMaxId);
        // 插入specs数据
        List<SpecsDO> specsToInsert = reqDTO.getNewSpecs().stream()
                .map(specs -> {
                    SpecsDO newSpecs = BeanUtil.copyProperties(specs, SpecsDO.class);
                    newSpecs.setId(specsIdGenerator.incrementAndGet()); // ID自增
                    newSpecs.setCommodityId(commodityId);
                    return newSpecs;
                }).toList();
        mongoTemplate.insertAll(specsToInsert);
    }

    @Override
    @Transactional
    public void updateCommodity(CommodityUpdateReqDTO requestParam) {
        // 将skuList第一个的price作为commodityPrice
        CommodityDO commodityDO = BeanUtil.copyProperties(requestParam, CommodityDO.class);
        commodityDO.setCommodityPrice(requestParam.getSkuList().getFirst().getPrice());
        // 取列表第一个作为商品封面
        commodityDO.setCoverImage(requestParam.getImgUrl().getFirst());
        commodityMapper.updateById(commodityDO);

        Query query = new Query(Criteria.where("commodityId").is(commodityDO.getCommodityId()));
        // 保存轮播图使用save方法覆盖MongoDB数据，if可以去掉
        if (Objects.nonNull(requestParam.getImgUrl())) {
            // 查询旧数据获取ID
            List<CarouselImagesDO> oldList = mongoTemplate.find(query, CarouselImagesDO.class);
            CarouselImagesDO newImage = new CarouselImagesDO()
                    .setId(oldList.getFirst().getId())
                    .setCommodityId(commodityDO.getCommodityId())
                    .setImgUrl(requestParam.getImgUrl());
            mongoTemplate.save(newImage);
        }

        // 存入SKU数据
        // 删除旧数据
        mongoTemplate.remove(query, SkusDO.class);
        // 插入新数据（带商品ID关联）
        List<SkusDO> newSkus = requestParam.getSkuList().stream()
                .map(sku -> {
                    SkusDO skuDO = BeanUtil.copyProperties(sku, SkusDO.class);
                    skuDO.setId(IdWorker.getId()); // 使用雪花算法生成新ID
                    skuDO.setCommodityId(commodityDO.getCommodityId()); // 确保类型一致
                    return skuDO;
                }).collect(Collectors.toList());
        mongoTemplate.insertAll(newSkus);

        // 存入specs数据
        // 删除旧数据
        mongoTemplate.remove(query, SpecsDO.class);
        // 插入新数据（带商品ID关联）
        List<SpecsDO> newSpecs = requestParam.getNewSpecs().stream()
                .map(specs -> {
                    SpecsDO specsDO = BeanUtil.copyProperties(specs, SpecsDO.class);
                    specsDO.setId(IdWorker.getId()); // 使用雪花算法生成新ID
                    specsDO.setCommodityId(commodityDO.getCommodityId());
                    return specsDO;
                }).toList();
        mongoTemplate.insertAll(newSpecs);
    }

    @Override
    public synchronized void deleteCommodity(Long commodityId) throws Exception {
        // 删除Mysql中的数据
        commodityMapper.deleteById(commodityId);

        Query query = new Query(Criteria.where("commodityId").is(commodityId));
        // 获取商品图片列表
        List<String> carouselImagesDOS = mongoTemplate.find(query, CarouselImagesDO.class).getFirst().getImgUrl();
        // 从完整URL中提取OSS对象路径
        List<String> ossObjectPaths = carouselImagesDOS.stream()
                .map(url -> "commodity/" + url.substring(url.lastIndexOf("/") + 1))
                .toList();
        // 批量删除oss的商品图片
        AliOssUtil.deleteFile(ossObjectPaths);

        // 删除MongoDB数据
        mongoTemplate.remove(query, SkusDO.class);
        mongoTemplate.remove(query, CarouselImagesDO.class);
    }

}
